package com.example.ass7.geometryprimitives;

import java.util.ArrayList;
import java.util.List;

import com.example.ass7.Equation;

/**
 * @author Meirav Ben Izhak
 */
public class Rectangle {
    // class members:
    // corners:
    private Point leftUpCorner;
    private final Point leftDownCorner;
    private final Point rightUpCorner;
    private final Point rightDownCorner;
    // sizes:
    private final double rectangleWidth;
    private final double rectangleHeight;
    // ribs:
    private final Line up;
    private final Line left;
    private final Line down;
    private final Line right;
    // limits:
    private final double yHighest;
    private final double yLowest;
    private final double xHighest;
    private final double xLowest;

    // Create a new rectangle with location and width/height.
    /**
     * @param upperLeft
     *            upperLeft
     * @param width
     *            width
     * @param height
     *            height
     */
    public Rectangle(
        Point upperLeft, double width, double height) {
        this.leftUpCorner = upperLeft;
        this.rectangleWidth = width;
        this.rectangleHeight = height;
        // setting the rectangle's corners:
        this.rightUpCorner = new Point(upperLeft.getX()
                + width, upperLeft.getY());
        this.rightDownCorner = new Point(this.rightUpCorner.getX(),
                this.rightUpCorner.getY()
                        + height);
        this.leftDownCorner = new Point(this.leftUpCorner.getX(),
                this.rightDownCorner.getY());
        // setting the lines of the rectangle
        this.up = new Line(this.leftUpCorner, this.rightUpCorner);
        this.right = new Line(this.rightUpCorner, this.rightDownCorner);
        this.down = new Line(this.leftDownCorner, this.rightDownCorner);
        this.left = new Line(this.leftDownCorner, this.leftUpCorner);
        // setting the rectangle's borders- important for block detection:
        this.yHighest = this.leftDownCorner.getY();
        this.yLowest = this.yHighest
                - this.getHeight();
        this.xHighest = this.rightDownCorner.getX();
        this.xLowest = this.xHighest
                - this.getWidth();
    }

    // getters for the lines:

    /**
     * @return Line
     */
    public Line getUp() {
        Line toReturn = this.up;
        return toReturn;
    }

    /**
     * @return Line
     */
    public Line getRight() {
        Line toReturn = this.right;
        return toReturn;
    }

    /**
     * @return Line
     */
    public Line getDown() {
        Line toReturn = this.down;
        return toReturn;
    }

    /**
     * @return Line
     */
    public Line getLeft() {
        Line toReturn = this.left;
        return toReturn;
    }

    /**
     * @param toSet
     *            toSet
     */
    public void setUpperLeftPoint(Point toSet) {
        this.leftUpCorner = toSet;
    }

    /**
     * @return the array of lines.
     */
    public Line[] returnRectanglesLines() {
        Line[] linesArray = new Line[4];
        // up
        linesArray[0] = this.up;
        // left
        linesArray[1] = this.left;
        // down
        linesArray[2] = this.down;
        // right
        linesArray[3] = this.right;

        return linesArray;
    }

    /**
     * @param trajectoryEnd
     *            trajectoryEnd
     * @return boolean
     */
    public boolean lineCrossesYLimits(Point trajectoryEnd) {
        double ballNextY = trajectoryEnd.getY();
        return (ballNextY >= this.yLowest && ballNextY <= this.yHighest);
    }

    /**
     * @param trajectoryEnd
     *            trajectoryEnd
     * @return boolean
     */
    public boolean lineCrossesXLimits(Point trajectoryEnd) {
        double ballNextX = trajectoryEnd.getX();
        return (ballNextX >= this.xLowest && ballNextX <= this.xHighest);
    }

    /**
     * @return Equation[]
     */
    public Equation[] returnRectanglesEquations() {
        Line[] linesArray = this.returnRectanglesLines();
        Equation[] equationArray = new Equation[4];
        for (int i = 0; i < 4; i++) {
            equationArray[i] = new Equation(linesArray[i]);
        }
        return equationArray;
    }

    /**
     * @param line
     *            line
     * @return List<Point>
     */
    public List<Point> intersectionPoints(Line line) {
        Line[] rectangleLines = this.returnRectanglesLines();
        List<Point> listToReturn = new ArrayList<Point>();
        listToReturn = this.intersectionPoints(line, rectangleLines);
        return listToReturn;
    }

    /**
     * @param line
     *            line
     * @param checkIntersetionsWith
     *            checkIntersetionsWith
     * @return Line[]
     */
    public List<Point> intersectionPoints(Line line,
            Line[] checkIntersetionsWith) {

        List<Point> intersections = new ArrayList<Point>();

        for (int iter = 0; iter < checkIntersetionsWith.length; iter++) {
            Point intersection = checkIntersetionsWith[iter]
                    .intersectionWith(line);
            if (intersection != null) {
                // intersections.add(intersection);
                intersections.add(intersection);
            }
        }
        return intersections;
    }

    // finds intersections between Equations- in order to calculate the ball's
    // movement while only the velocity and direction is known
    // /////working :)
    /**
     * @param equation
     *            equation
     * @return List<Point>
     */
    public List<Point> intersectionWithEquations(Equation equation) {
        List<Point> intersections = new ArrayList<Point>();
        Equation[] equations = this.returnRectanglesEquations();

        for (int iter = 0; iter < 4; iter++) {
            Point intersection = equations[iter].getIntersection(equation);
            if (intersection != null) {
                intersections.add(intersection);
                // intersections.add(intersection);
            }
        }
        return intersections;
    }

    // Return the width and height of the rectangle
    /**
     * @return double
     */
    public double getWidth() {
        double widthToReturn = this.rectangleWidth;
        return widthToReturn;
    }

    /**
     * @return double
     */
    public double getHeight() {
        double heightToReturn = this.rectangleHeight;
        return heightToReturn;
    }

    // Returns the upper-left point of the rectangle.
    /**
     * @return Point
     */
    public Point getUpperLeft() {
        Point pointToReturn = this.leftUpCorner;
        return pointToReturn;
    }

    /**
     * @param collisionPoint
     *            collisionPoint
     * @return String
     */
    public String findWhichRibWillBeHit(Point collisionPoint) {
        String toReturn = new String();
        if (this.getUp().isIntersectionInLine(collisionPoint)) {
            toReturn = "UP";
        }
        if (this.getDown().isIntersectionInLine(collisionPoint)) {
            toReturn = "DOWN";
        }
        if (this.getLeft().isIntersectionInLine(collisionPoint)) {
            toReturn = "LEFT";
        }
        if (this.getRight().isIntersectionInLine(collisionPoint)) {
            toReturn = "RIGHT";
        }
        return toReturn;
    }

    /**
     * @return double
     */
    public double getyHighest() {
        return this.yHighest;
    }

    /**
     * @return double
     */
    public double getyLowest() {
        return this.yLowest;
    }

    /**
     * @return double
     */
    public double getxHighest() {
        return this.xHighest;
    }

    /**
     * @return double
     */
    public double getxLowest() {
        return this.xLowest;
    }

}